package kd.bos.openapi.sdk.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import kd.bos.openapi.sdk.exception.APIException;
import kd.bos.openapi.sdk.login.dto.AccessTokenDto;
import kd.bos.openapi.sdk.login.dto.AppTokenDto;
import kd.bos.openapi.sdk.response.result.ResultCode;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author johnz
 * @Deacription 基础API服务类
 * @date 2022年4月6日
 */
@Slf4j
public class OpenApiUtil {
    // 获取appTokenUrl
    private static final String GET_APP_TOKEN_URL = "api/getAppToken.do";
    // 获取accessTokenUrl
    private static final String GET_ACCESS_TOKEN_URL = "api/login.do";
    // accessToken
    private static AccessTokenDto accessToken;

    // 根据环境基本URL前缀
    protected static String getBaseUrl() {
        String baseUrl = PropertyUtil.getProperty("bos.env.cosmic");
        return baseUrl;
    }

    /**
     * 获取accessToken，如果accessToken为空或无效，从新获取AccessToken
     * @return
     * @throws APIException
     */
    public static AccessTokenDto getAccessToken() throws APIException {
        if (accessToken == null || accessToken.isExpire()) {
            accessToken = getBosAccessToken();
        }
        return accessToken;
    }

    /**
     * 获取appToken方法
     * @param appId 第三方应用/基本信息/系统编码
     * @param appSecuret 第三方应用/认证方式为AccessToken认证/AccessToken加密认证密钥
     * @param accountId 苍穹平台数据中心
     * @param tenantId 苍穹平台租户ID
     * @param language 访问使用的语言，如中文 zh_CN
     * @return appToken
     * @throws APIException 异常
     */
    public static AppTokenDto getAppToken(String appId, String appSecuret, String accountId,
                                          String tenantId, String language) throws APIException {
        if (StringUtils.isEmpty(appId) || StringUtils.isEmpty(appSecuret)
                || StringUtils.isEmpty(accountId) || StringUtils.isEmpty(tenantId)) {
            throw APIException.of(ResultCode.BUSINESS_PARAM_NULL_EXCEPTION);
        }
        AppTokenDto appToken = new AppTokenDto();
         // 获取appToken
        String getAppTokenUrl = getBaseUrl() + GET_APP_TOKEN_URL;
        Map<String, Object> params = new HashMap<>();
        params.put("appId", appId);
        params.put("appSecuret", appSecuret);
        params.put("tenantid", tenantId);
        params.put("accountId", accountId);
        params.put("language", language);
        String res = HttpClientUtil.post(getAppTokenUrl, new HashMap<>(), params);

        if (StringUtils.isEmpty(res)) {
            throw APIException.of(ResultCode.BUSINESS_FAILURE_EXCEPTION, "get appToken res error!");
        }

        JSONObject data = JSON.parseObject(res).getJSONObject("data");
        appToken.setAppToken(data.getString("app_token"));
        appToken.setExpireDate(data.getDate("expire_time"));
        return appToken;
    }

    /**
     * 获取accessToken方法
     * @param userId 登录苍穹用户ID
     * @param userPwd 登录苍穹用户密码
     * @param appToken appToken
     * @param accountId 苍穹平台数据中心
     * @param tenantId 苍穹平台租户ID
     * @param userType 登录苍穹用户类型，如Mobile
     * @return 访问accessToken
     * @throws APIException 异常
     */
    public static AccessTokenDto getAccessToken(String userId, String userPwd, AppTokenDto appToken, String accountId,
                                                String tenantId, String userType) throws APIException {
        if (StringUtils.isEmpty(userId) || appToken == null || StringUtils.isEmpty(appToken.getAppToken())
                || StringUtils.isEmpty(accountId) || StringUtils.isEmpty(tenantId)) {
            throw APIException.of(ResultCode.BUSINESS_PARAM_NULL_EXCEPTION);
        }
        AccessTokenDto accessToken = new AccessTokenDto();
        accessToken.setAppToken(appToken);
        Map<String, Object> params = new HashMap<>();
        // 获取accessToken
        String getAccessTokenUrl = getBaseUrl() + GET_ACCESS_TOKEN_URL;
        params.put("user", userId);
        params.put("apptoken", appToken.getAppToken());
        params.put("tenantid", tenantId);
        params.put("accountId", accountId);
        params.put("usertype", userType);
        log.info("getAccessTokenUrl params:{}, url:{}", JSON.toJSONString(params), getAccessTokenUrl);
        String res = HttpClientUtil.post(getAccessTokenUrl, new HashMap<>(), params);
        if (StringUtils.isEmpty(res)) {
            throw APIException.of(ResultCode.BUSINESS_FAILURE_EXCEPTION, "get accessToken error!");
        }
        JSONObject data = JSON.parseObject(res).getJSONObject("data");
        accessToken.setAccessToken(data.getString("access_token"));
        Date accessTokenExpireDate = data.getDate("expire_time");
        // 比较appToken和AccessToken的失效时间，失效时间早的放入accessToken的失效时间中
        if (accessToken.getAppToken().getExpireDate().after(accessTokenExpireDate)) {
            accessToken.setExpireDate(accessTokenExpireDate);
        }else{
            accessToken.setExpireDate(accessToken.getAppToken().getExpireDate());
        }
        // 将accessToken失效时间延长2小时
        accessToken.setExpireDate(DateUtil.addDateHours(accessToken.getExpireDate(), Integer.parseInt(PropertyUtil.getProperty("bos.token.expireHours"))));
        return accessToken;
    }

    /**
     * 获取苍穹AccessToken
     * @return
     * @throws APIException
     */
    private static AccessTokenDto getBosAccessToken() throws APIException {
        if (accessToken == null) {
            accessToken = new AccessTokenDto();
        }
        // 获取appToken
        AppTokenDto appToken = getAppToken(PropertyUtil.getProperty("bos.appId"), PropertyUtil.getProperty("bos.appSecuret")
                , PropertyUtil.getProperty("bos.cosmic.accountId"), PropertyUtil.getProperty("bos.cosmic.tenantId"), PropertyUtil.getProperty("bos.language"));

        // 获取accessToken
        accessToken = getAccessToken(PropertyUtil.getProperty("bos.userId"), PropertyUtil.getProperty("bos.userPwd"),
                appToken, PropertyUtil.getProperty("bos.cosmic.accountId"), PropertyUtil.getProperty("bos.cosmic.tenantId"), PropertyUtil.getProperty("bos.userType"));

        log.info("accessToken:{}", JSON.toJSONString(accessToken));
        return accessToken;
    }

    /**
     * 通过对象参数作为body,处理post请求
     *
     * @param sortUrl
     * @param jsonObj
     * @return
     * @throws Exception
     */
    public static String doPostByJson(String sortUrl, Object jsonObj) throws APIException {
        String url = getBaseUrl() + sortUrl;
        Map<String, String> header = new HashMap<>();
        header.put("accesstoken", getAccessToken().getAccessToken());
        return HttpClientUtil.post(url, header, jsonObj);
    }


    /**
     * 通过对象参数作为body,处理post请求
     *
     * @param sortUrl
     * @param header 请求头
     * @param jsonObj
     * @return
     * @throws Exception
     */
    public static String doPostByJson(String sortUrl, Map<String,String> header, Object jsonObj) throws APIException {
        // 构建完整的访问URL
        String url = getBaseUrl() + sortUrl;
        // 将accessToken放入请求头中
        header.put("accesstoken", getAccessToken().getAccessToken());
        return HttpClientUtil.post(url, header, jsonObj);
    }

    /**
     * 通过对象参数作为body,处理post请求
     *
     * @param sortUrl
     * @param header 请求头
     * @param requestBodyXml
     * @return
     * @throws Exception
     */
    public static String doPostByXml(String sortUrl, Map<String,String> header, String requestBodyXml) throws APIException {
        // 构建完整的访问URL
        String url = getBaseUrl() + sortUrl;
        // 将accessToken放入请求头中
        header.put("accesstoken", getAccessToken().getAccessToken());
        return HttpClientUtil.post(url, header, requestBodyXml,false);
    }

    /**
     * 通过对象参数作为body,处理post请求
     *
     * @param sortUrl
     * @param params
     * @return
     * @throws Exception
     */
    public static String doGet(String sortUrl, Map<String,Object> params) throws APIException {
        // 构建完整的访问URL
        String url = getBaseUrl() + sortUrl;
        Map<String, String> header = new HashMap<>();
        // 将accessToken放入请求头中
        header.put("accesstoken", getAccessToken().getAccessToken());
        return HttpClientUtil.get(url,header, params);
    }
}